package cn.com.nes.site.service.crm.opportunity.impl;

import cn.com.nes.common.exception.MissBusinessParameterException;
import cn.com.nes.common.util.XzqhUtils;
import cn.com.nes.common.util.tree.TreeBuilder;
import cn.com.nes.mybatis.agent.crm.entity.OpportunityAreaCode;
import cn.com.nes.mybatis.agent.crm.mapper.OpportunityAreaCodeMapper;
import cn.com.nes.mybatis.agent.system.entity.SystemXzqh;
import cn.com.nes.site.entity.em.DeleteEnum;
import cn.com.nes.site.service.crm.opportunity.OpportunityAreaCodeService;
import cn.com.nes.site.service.crm.opportunity.bo.OpportunityAreaCodeBo;
import cn.com.nes.site.service.crm.opportunity.dto.OpportunityAreaCodeDTO;
import cn.com.nes.site.service.system.region.XzqhService;
import cn.com.nes.site.service.system.region.dto.RegionCodeTreeNode;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author yishuai
 */
@Slf4j
@Service
public class OpportunityAreaCodeServiceImpl extends ServiceImpl<OpportunityAreaCodeMapper, OpportunityAreaCode> implements OpportunityAreaCodeService {

    @Resource
    private XzqhService xzqhService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(OpportunityAreaCodeBo opportunityAreaCodeBo) throws Exception {
        log.debug("save opportunityAreaCodeBo:{}", opportunityAreaCodeBo);
        this.baseMapper.deleteByOpportunityUuid(opportunityAreaCodeBo);

        List<OpportunityAreaCode> list = new ArrayList<>();
        for (OpportunityAreaCodeDTO areaCode : opportunityAreaCodeBo.getAreaCodes()) {
            OpportunityAreaCode opportunityAreaCode = new OpportunityAreaCode();
            opportunityAreaCode.setAreaCode(areaCode.getXzqhdm());
            opportunityAreaCode.setAreaCodeName(areaCode.getXzqhmc());
            opportunityAreaCode.setOpportunityUuid(opportunityAreaCodeBo.getOpportunityUuid());
            opportunityAreaCode.setProjectUuid(opportunityAreaCodeBo.getProjectUuid());
            opportunityAreaCode.setDeleted(DeleteEnum._0.getKey());
            opportunityAreaCode.setGmtCreate(opportunityAreaCodeBo.getOperateDate());
            opportunityAreaCode.setGmtCreateId(opportunityAreaCodeBo.getOperateUserId());
            opportunityAreaCode.setGmtModified(opportunityAreaCodeBo.getOperateDate());
            opportunityAreaCode.setGmtModifiedId(opportunityAreaCodeBo.getOperateUserId());
            list.add(opportunityAreaCode);
        }
        this.saveBatch(list);
    }

    @Override
    public List<String> getOpportunityIdListByAreaCode(String areaCode) {
        // 循环获取所有直属上级的行政区划代码
        List<String> parentAreaCodeList = new ArrayList<>();
        for (int i = XzqhUtils.getRegionLevel(areaCode); i > 0; i--) {
            String regionCodePrefix = XzqhUtils.getRegionCodePrefix(areaCode, i);
            if (i != 1) {
                // 如果不是一级需要补全后面的0
                regionCodePrefix = StrUtil.padAfter(regionCodePrefix, 12, '0');
            }
            parentAreaCodeList.add(regionCodePrefix);
        }

        // 获取本级的行政区划代码有效位
        String regionCodePrefix = XzqhUtils.getRegionCodePrefix(areaCode);

        return this.baseMapper.getOpportunityIdListByAreaCode(parentAreaCodeList, regionCodePrefix);
    }

    @Override
    public List<OpportunityAreaCodeDTO> getAreaCodesByOpportunityUuid(String opportunityUuid) throws Exception {
        if (StrUtil.isEmpty(opportunityUuid)) {
            throw new MissBusinessParameterException("opportunityUuid must not be empty");
        }
        return this.baseMapper.getOpportunityAreaCodeDtos(opportunityUuid);
    }

    /**
     * Retrieves the hierarchical tree of region codes associated with a given opportunity.
     *
     * @param opportunityUuid The unique identifier for the opportunity. Must not be empty.
     * @return A list of {@link RegionCodeTreeNode} representing the hierarchical tree structure of region codes
     *         set for the opportunity, starting with the '全国' node at the root. Returns an empty list if no
     *         regions are set for the opportunity.
     * @throws Exception If the opportunityUuid is empty, throwing a MissBusinessParameterException.
     */
    @Override
    public List<RegionCodeTreeNode> getRegionCodeTreeForOpportunity(String opportunityUuid) throws Exception {
        if (StrUtil.isEmpty(opportunityUuid)) {
            throw new MissBusinessParameterException("opportunityUuid must not be empty");
        }
        // 1、查询商务项目设置的所有区划代码
        List<String> opportunityAllRegions = this.getAllCoverRegionsForOpportunity(opportunityUuid);
        if (CollectionUtil.isEmpty(opportunityAllRegions)) {
            return Collections.emptyList();
        }

        // 2、查询所有的第5级区划代码
        List<RegionCodeTreeNode> regionCodeList = xzqhService.getRegionCodeList(opportunityAllRegions);
        List<RegionCodeTreeNode> fifthLevelRegions = regionCodeList.stream()
                .filter(regionCodeTreeNode -> regionCodeTreeNode.getRegionLevel() == 5)
                .collect(Collectors.toList());

        // 3、递归所有上级行政区划
        List<String> opportunitySettingRegions = new ArrayList<>();
        for (int i = 5; i > 0; i--) {
            int finalI = i;
            List<String> parentRegionCodes = fifthLevelRegions.stream()
                    .map(regionCodeTreeNode -> XzqhUtils.getParentRegionCode(regionCodeTreeNode.getId(), finalI))
                    .distinct()
                    .collect(Collectors.toList());
            System.out.println(parentRegionCodes);
            opportunitySettingRegions.addAll(parentRegionCodes);
        }

        // 4、 组装树
        List<RegionCodeTreeNode> regionCodeTreeNodes = xzqhService.getRegionCodeList(opportunitySettingRegions);
        regionCodeTreeNodes.add(0, new RegionCodeTreeNode("86", "全国", null));
        return new TreeBuilder<RegionCodeTreeNode>().buildTree(regionCodeTreeNodes).get(0).getChildren();
    }

    /**
     * Retrieves the list of region codes associated with a specific opportunity setting.
     *
     * @param opportunityUuid The unique identifier for the opportunity whose region settings are to be fetched.
     * @return A list of {@link RegionCodeTreeNode} representing the region codes configured for the given opportunity,
     *         or an empty list if no regions are set.
     * @throws MissBusinessParameterException If the provided opportunityUuid is empty.
     */
    private List<RegionCodeTreeNode> getRegionCodesForOpportunitySetting(String opportunityUuid) {
        if (StrUtil.isEmpty(opportunityUuid)) {
            throw new MissBusinessParameterException("opportunityUuid must not be empty");
        }
        List<String> opportunitySettingRegions = this.baseMapper.getOpportunitySettingRegions(opportunityUuid);
        if (CollectionUtil.isEmpty(opportunitySettingRegions)) {
            return Collections.emptyList();
        }
        return xzqhService.getRegionCodeList(opportunitySettingRegions);
    }


    /**
     * Retrieves all the coverage regions associated with a given opportunity.
     *
     * @param opportunityUuid The unique identifier for the opportunity. Must not be empty.
     * @return A list of strings representing the unique codes for all covered regions related to the opportunity.
     *         Returns an empty list if no coverage regions are set.
     * @throws Exception If the 'opportunityUuid' parameter is empty, throwing a MissBusinessParameterException.
     */
    @Override
    public List<String> getAllCoverRegionsForOpportunity(String opportunityUuid) throws Exception {
        if (StrUtil.isEmpty(opportunityUuid)) {
            throw new MissBusinessParameterException("opportunityUuid must not be empty");
        }
        List<RegionCodeTreeNode> areaCodes = this.getRegionCodesForOpportunitySetting(opportunityUuid);
        if (CollectionUtil.isEmpty(areaCodes)) {
            return Collections.emptyList();
        }

        // 获取当前权限的行政区划
        List<String> setAreaCodes = areaCodes.stream()
                .map(RegionCodeTreeNode::getId)
                .distinct()
                .collect(Collectors.toList());
        List<SystemXzqh> systemXzqhs = (List<SystemXzqh>) xzqhService.listByIds(setAreaCodes);

        // 1、只有上级代码，获取所有子行政区划
        // 2、有上级及部分下级代码，获取下级的所有行政区划代码
        for (SystemXzqh systemXzqh : systemXzqhs) {
            // 获取当前行政区划代码级别
            String regionCodePrefix = XzqhUtils.getRegionCodePrefix(systemXzqh.getXzqhdm());
            boolean match = systemXzqhs.stream()
                    .filter(xzqh -> !xzqh.getXzqhdm().equals(systemXzqh.getXzqhdm()))
                    .anyMatch(xzqh -> xzqh.getXzqhdm().startsWith(regionCodePrefix));
            if (match) {
                log.info("符合匹配 - {}", systemXzqh.getXzqhdm());
            } else {
                List<SystemXzqh> areacodes = xzqhService.getListByPrefix(regionCodePrefix);
                if (CollUtil.isNotEmpty(areacodes)) {
                    setAreaCodes.addAll(areacodes.stream()
                            .map(SystemXzqh::getXzqhdm)
                            .filter(xzqh -> !xzqh.equals(systemXzqh.getXzqhdm()))
                            .collect(Collectors.toList()));
                }
            }
        }
        return setAreaCodes.stream().distinct().collect(Collectors.toList());
    }

    /**
     * Retrieves a list of region code tree nodes associated with a given opportunity and an optional higher-level region code.
     *
     * This method constructs a hierarchical tree structure representing region codes linked to a specific opportunity.
     * It allows filtering these regions based on a higher-level region code to focus on a subset of the geographical hierarchy.
     *
     * @param opportunityUuid The unique identifier for the opportunity that the region codes must be related to.
     *                        Must not be null or empty.
     * @param higherRegionCode An optional code specifying a higher-level region to filter the results.
     *                         If provided, only regions within this higher-level region will be included.
     *                         Can be null to include all regions associated with the opportunity.
     * @return A list of {@link RegionCodeTreeNode} instances, each representing a region code with its hierarchical context.
     *         The tree nodes include details such as the region's full name, level, and geographical coordinates.
     * @throws Exception If there is an issue retrieving the data, such as a failure in accessing the underlying storage or invalid parameters.
     */
    @Override
    public List<RegionCodeTreeNode> getRegionCodesForOpportunity(String opportunityUuid,
            String higherRegionCode) throws Exception {
        if (StrUtil.isEmpty(opportunityUuid)) {
            throw new MissBusinessParameterException("opportunityUuid must not be empty");
        }
        List<String> opportunityAllRegions = this.getAllCoverRegionsForOpportunity(opportunityUuid);
        if (CollectionUtil.isEmpty(opportunityAllRegions)) {
            return Collections.emptyList();
        }
        List<String> regionCodeList = opportunityAllRegions.stream()
                .filter(xzqh -> xzqh.startsWith(XzqhUtils.getRegionCodePrefix(higherRegionCode)))
                .collect(Collectors.toList());

        List<String> list = regionCodeList.stream()
                .map(regionCodeTreeNode -> XzqhUtils.getParentRegionCode(regionCodeTreeNode, XzqhUtils.getRegionLevel(higherRegionCode) + 1))
                .collect(Collectors.toList());

        List<RegionCodeTreeNode> regionCodeList1 = xzqhService.getRegionCodeList(list);

        return regionCodeList1.stream()
                .filter(regionCodeTreeNode -> regionCodeTreeNode.getParentId().equals(higherRegionCode))
                .collect(Collectors.toList());
    }

}




